package com.xique.door.biz.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.xique.common.core.domain.R;
import com.xique.common.core.text.Convert;
import com.xique.common.core.utils.OrikaUtil;
import com.xique.common.core.utils.SecurityUtils;
import com.xique.common.core.utils.StringUtils;
import com.xique.common.core.web.domain.AjaxResult;
import com.xique.door.api.request.build.RemoteBuildingListRequest;
import com.xique.door.bean.dao.FloorHouseDao;
import com.xique.door.bean.domain.*;
import com.xique.door.bean.request.AccessDevice.AccessDeviceListRequest;
import com.xique.door.bean.request.buildBuildng.BuildBuildingAddRequest;
import com.xique.door.bean.request.buildBuildng.BuildBuildingDeleteRequest;
import com.xique.door.bean.request.buildBuildng.BuildBuildingEditRequest;
import com.xique.door.bean.request.buildBuildng.BuildBuildingListRequest;
import com.xique.door.bean.request.deviceUser.DeviceDeleteUserRequest;
import com.xique.door.bean.search.build.BuildingListSearch;
import com.xique.door.bean.vo.area.BuildingListVO;
import com.xique.door.biz.service.IBuildBuildingBizService;
import com.xique.door.biz.service.IBuildingDeviceBizService;
import com.xique.door.biz.service.IDeviceUserBizService;
import com.xique.door.mapper.AccessDeviceMapper;
import com.xique.door.service.*;
import com.xique.door.service.impl.UserDeviceServiceImpl;
import com.xique.door.util.BuildUtils;
import org.apache.catalina.security.SecurityUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import sun.misc.Request;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author shd
 * @create 2021/9/10 15:00
 */
@Service
public class BuildBuildingBizServiceImpl implements IBuildBuildingBizService {

    @Autowired
    private IBuildAreaService areaService;

    @Autowired
    private IBuildBuildingService buildBuildingService;

    @Autowired
    private IBuildAreaService buildAreaService;

    @Autowired
    private IBuildHouseService buildHouseService;

    @Autowired
    private IAccessDeviceService deviceService;

    @Autowired
    private IBuildingDeviceService buildingDeviceService;

    @Autowired
    private IBuildingDeviceBizService buildingDeviceBizService;

    @Autowired
    private IParkInfoService parkInfoService;

    @Autowired
    AccessDeviceMapper accessDeviceMapper;

    @Autowired
    private UserDeviceServiceImpl userDeviceService;

    //删除设备上得用户信息
    @Autowired
    private IDeviceUserBizService deviceUserBizService;

    // 删除设备上的卡片信息
    @Autowired
    private IDCardService idCardService;

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public AjaxResult batchAddBuilding(BuildBuildingAddRequest request) {
        /**
         * TODO
         * 1、检测参数是否合法，编号是否重复
         * 2、生成对应的楼栋，单元，楼层，房屋数据
         * 3、生成对应的权限组
         */
        // 可行性验证
        AjaxResult result = checkBuildBuildingAddRequest(request);
        if (AjaxResult.isError(result)) {
            return result;
        }

        ParkInfo parkInfo = parkInfoService.selectParkInfoById(request.getParkId());

        List<BuildBuilding> buildBuildings = new ArrayList<>();
        BuildArea area = buildAreaService.selectBuildAreaById(request.getAreaId());
        for (int i = request.getBuildingStartNum(); i < request.getBuildingEndNum() + 1; i++) {
            for (Integer j = 1; j < request.getUnitNum() + 1; j++) {
                BuildBuilding building = OrikaUtil.convert(request, BuildBuilding.class);
                String buildCode = String.valueOf(i);
                String unitCode = String.valueOf(j);
                if (String.valueOf(i).length() == 1) {
                    buildCode = "0" + i;
                }
                if (String.valueOf(j).length() == 1) {
                    unitCode = "0" + j;
                }
                building.setUnitCode(unitCode);
                building.setBuildingCode(buildCode);
                building.setCode(area.getCode() + buildCode + unitCode);
                if (StringUtils.isEmpty(building.getBuildingName())) {
                    building.setBuildingName(i + "幢" + j + "单元");
                }
                buildBuildings.add(building);
            }
        }
        int count = buildBuildingService.batchInsertBuildings(buildBuildings);
        if (count <= 0) {
            return AjaxResult.error("楼栋添加失败");
        }

        // TODO 楼栋设备绑定
        buildingDeviceBizService.insertBuildingDevice(buildBuildings);

        if (!request.getAutoAddHouseFlag()) {
            return AjaxResult.success();
        }

        int floorNumber = request.getFloorNumber() == null ? 0 : request.getFloorNumber();
        int houseNumber = request.getHouseNumber() == null ? 0 : request.getHouseNumber();
        List<BuildHouse> houses = new ArrayList<>();

        //批量生成房屋
        for (BuildBuilding buildBuilding : buildBuildings) {
            for (int i = 1; i <= floorNumber; i++) {
                for (int j = 1; j <= houseNumber; j++) {
                    BuildHouse house = new BuildHouse();
                    house.setParkId(request.getParkId());
                    house.setBuildingId(buildBuilding.getId());
                    house.setBuildingName(buildBuilding.getBuildingName());
                    int tempHouseNum = j;
                    if (request.getSerialCodeFlag() && Integer.parseInt(buildBuilding.getUnitCode()) > 1) {
                        //单元房号编码连续 && 超过一个单元
                        tempHouseNum = request.getHouseNumber() * (Integer.parseInt(buildBuilding.getUnitCode()) - 1) + j;
                    }
                    house.setFloor((long) i);
                    //4位房号
                    house.setHouseCode(BuildUtils.getCode(BuildUtils.getCode("", String.valueOf(i)), String.valueOf(tempHouseNum)));
                    //对讲编号
                    house.setCode(buildBuilding.getCode() + house.getHouseCode());
                    house.setHouseName(house.getHouseCode() + "室");

                    house.setDelFlag("0");
                    if (parkInfo.getMaxInNumber() == null) {
                        house.setMaxInNumber(10);
                    } else {
                        house.setMaxInNumber(parkInfo.getMaxInNumber());
                    }
                    house.setStatus("normal");

                    houses.add(house);
                }
            }
        }
        count = buildHouseService.insertBuildHouses(houses);
        if (count <= 0) {
            return AjaxResult.error("添加失败");
        }

        return AjaxResult.success("添加成功");
    }

    private AjaxResult checkBuildBuildingAddRequest(BuildBuildingAddRequest request) {
        if (null == request.getAreaId() || request.getAreaId() == 0) {
            return AjaxResult.error("请传入区域");
        }

        if (request.getBuildingStartNum() == null || request.getBuildingEndNum() == null) {
            return AjaxResult.error("请输入楼栋编号");
        }

        if (request.getUnitNum() == null) {
            return AjaxResult.error("请输入单元数");
        }

        if (request.getAutoAddHouseFlag()) {

            if (request.getHouseNumber() == null) {
                return AjaxResult.error("请输入每层户数");
            }

            if (request.getFloorNumber() == null) {
                return AjaxResult.error("请输入地面层数");
            }
        }

        BuildArea area = buildAreaService.selectBuildAreaById(request.getAreaId());

        for (int i = request.getBuildingStartNum(); i < request.getBuildingEndNum() + 1; i++) {
            for (Integer j = 1; j < request.getUnitNum() + 1; j++) {
                String buildCode = String.valueOf(i);
                String unitCode = String.valueOf(j);
                if (String.valueOf(i).length() == 1) {
                    buildCode = "0" + i;
                }
                if (String.valueOf(j).length() == 1) {
                    unitCode = "0" + j;
                }
                BuildBuilding search = new BuildBuilding();
                search.setParkId(request.getParkId());
                search.setCode(area.getCode() + buildCode + unitCode);
                List<BuildBuilding> list = buildBuildingService.selectBuildBuildingList(search);
                if (CollectionUtils.isNotEmpty(list)) {
                    return AjaxResult.error("楼栋单元编号重复！");
                }
            }
        }
        return AjaxResult.success();
    }

    @Override
    public AjaxResult buildingEdit(BuildBuildingEditRequest request) {
        BuildBuilding building = OrikaUtil.convert(request, BuildBuilding.class);
        int count = buildBuildingService.updateBuildBuilding(building);
        if (count <= 0) {
            return AjaxResult.error("编辑失败");
        }
        return AjaxResult.success("编辑成功");
    }

    @Override
    public AjaxResult buildingDelete(BuildBuildingDeleteRequest request) {
        List<BuildHouse> houseList = buildHouseService.selectBuildHouseListByBuildingIds(Arrays.asList(Convert.toLongArray(request.getIds())));
        if (CollectionUtils.isNotEmpty(houseList)) {
            return AjaxResult.error("请先删除该楼栋下的房屋");
        }
        int count = buildBuildingService.deleteBuildBuildingByIds(request.getIds());
        if (count <= 0) {
            return AjaxResult.error("删除失败");
        }
        return AjaxResult.success("删除成功");
    }

    @Override
    public BuildBuilding selectBuildBuildingById(Long id) {
        BuildBuilding buildBuilding = buildBuildingService.selectBuildBuildingById(id);
        BuildHouse buildHouse = new BuildHouse();
        buildHouse.setBuildingId(buildBuilding.getId());
        List<FloorHouseDao> floorHouseDaos = buildHouseService.selectFloorHouseList(buildHouse);
//        List<BuildHouse> buildHouses = buildHouseService.selectBuildHouseList(buildHouse);
//        Map<Long, List<BuildHouse>> buildHouseList = buildHouses.stream().collect(Collectors.groupingBy(BuildHouse::getFloor));
        buildBuilding.setFloorHouseDaos(floorHouseDaos);
        return buildBuilding;
    }

    @Override
    public AjaxResult addBuilding(BuildBuildingAddRequest request) {
        BuildArea area = buildAreaService.selectBuildAreaById(request.getAreaId());
        BuildBuilding building = OrikaUtil.convert(request, BuildBuilding.class);
        String code = request.getCode();
        building.setUnitCode(code.substring(0, 2));
        building.setBuildingCode(code.substring(2));
        building.setCode(area.getCode() + code);

        // 判断code是否重复
        BuildBuilding search = new BuildBuilding();
        search.setParkId(request.getParkId());
        search.setCode(building.getCode());
        List<BuildBuilding> list = buildBuildingService.selectBuildBuildingList(search);
        if (CollectionUtils.isNotEmpty(list)) {
            return AjaxResult.error("楼栋单元编号重复了，请重新输入");
        }

        buildBuildingService.insertBuildBuilding(building);

        // TODO 楼栋设备绑定
        buildingDeviceBizService.insertBuildingDevice(Collections.singletonList(building));

        return AjaxResult.success();
    }

//     @Override
//     public List<AccessDevice> selectBuildingDevices(Long id) {
// //        AccessDevice areaDeviceSearch = new AccessDevice();
// //        BuildBuilding buildBuilding = buildBuildingService.selectBuildBuildingById(id);
// //        areaDeviceSearch.setForeignId(buildBuilding.getAreaId());
// //        List<AccessDevice> areaDevices = deviceService.selectAccessDeviceList(areaDeviceSearch);
//         BuildingDevice buildingDevice = new BuildingDevice();
//         buildingDevice.setBuildingId(id);
//         List<BuildingDevice> buildingDevices = buildingDeviceService.selectBuildingDeviceList(buildingDevice);
//         List<Long> deviceIds = buildingDevices.stream().map(BuildingDevice::getDeviceId).collect(Collectors.toList());
//         // return deviceService.selectAccessDeviceByIds(deviceIds);
//
//        List<AccessDevice> accessDevices = new ArrayList<>();
//        for (Long deviceId : deviceIds) {
//            AccessDevice accessDevice = deviceService.selectAccessDeviceById(deviceId);
//            accessDevices.add(accessDevice);
//        }
//        return accessDevices;
//
//     }

    @Override
    public List<AccessDeviceListRequest> selectBuildingDevices(Long id) {
//        AccessDevice areaDeviceSearch = new AccessDevice();
//        BuildBuilding buildBuilding = buildBuildingService.selectBuildBuildingById(id);
//        areaDeviceSearch.setForeignId(buildBuilding.getAreaId());
//        List<AccessDevice> areaDevices = deviceService.selectAccessDeviceList(areaDeviceSearch);
        BuildingDevice buildingDevice = new BuildingDevice();
        buildingDevice.setBuildingId(id);
        List<BuildingDevice> buildingDevices = buildingDeviceService.selectBuildingDeviceList(buildingDevice);
        // List<Long> deviceIds = buildingDevices.stream().map(BuildingDevice::getDeviceId).collect(Collectors.toList());
        // // return deviceService.selectAccessDeviceByIds(deviceIds);
        //
        // List<AccessDevice> accessDevices = new ArrayList<>();
        // for (Long deviceId : deviceIds) {
        //     AccessDevice accessDevice = deviceService.selectAccessDeviceById(deviceId);
        //     accessDevices.add(accessDevice);
        // }

        List<AccessDeviceListRequest> arrayList = new ArrayList<>();
        buildingDevices.forEach(i -> {
            AccessDeviceListRequest ascId = new AccessDeviceListRequest();
            ascId.setId(i.getId());
            AccessDevice accessDevice = deviceService.selectAccessDeviceById(i.getDeviceId());
            if (StringUtils.isNotNull(accessDevice)) {
                ascId.setName(accessDevice.getName());
                arrayList.add(ascId);
            }
        });

        return arrayList;

    }


    @Override
    public AjaxResult delBuildingDevices(List<Long> ids) {
        if (ids != null && ids.size() > 0) {
            for (Long id : ids) {
                // 删除设备和楼栋表之间的数据
                buildingDeviceService.deleteBuildingDeviceById(id);
                // 获取设备id
                BuildingDevice buildingDevice = buildingDeviceService.selectBuildingDeviceById(id);
                if (ObjectUtils.isNotEmpty(buildingDevice)) {
                    // 删除设备上得用户信息
                    DeviceDeleteUserRequest request = new DeviceDeleteUserRequest();
                    request.setParkId(SecurityUtils.getParkId());
                    request.setDeviceId(buildingDevice.getDeviceId());
                    List<UserDevice> userDevices = userDeviceService.selectUserDeviceByLists(buildingDevice.getDeviceId(), request.getParkId());
                    if (CollectionUtils.isNotEmpty(userDevices)) {
                        // 删除设备和用户表之间的数据
                        userDeviceService.deleteUserDeviceByDeviceId(buildingDevice.getDeviceId());
                        if (userDevices.size() == 1) {
                            request.setUserId(userDevices.get(0).getUserId());
                        } else {
                            List<Long> collect = userDevices.stream().map(UserDevice::getUserId).collect(Collectors.toList());
                            request.setUserIds(StringUtils.join(collect, ","));
                        }
                        deviceUserBizService.removeDeviceUser(request);

                        List<CardDevice> cardDevices = idCardService.selectDCardDeviceList(buildingDevice.getDeviceId());
                        if (CollectionUtils.isNotEmpty(cardDevices)) {
                            // 删除设备和卡片表之间的数据
                            idCardService.deleteDCardDeviceId(buildingDevice.getDeviceId());
                        }
                    }
                }
            }
        }
        return AjaxResult.success();
    }

    @Override
    public AjaxResult addBuildingDevices(List<Long> ids, Long buildBuildingId) {
        if (ids != null && ids.size() > 0) {
            ids.forEach(e -> {
                BuildingDevice buildingDevice = new BuildingDevice();
                buildingDevice.setBuildingId(buildBuildingId);
                buildingDevice.setParkId(SecurityUtils.getParkId());
                buildingDevice.setCreateBy(SecurityUtils.getUserId().toString());
                buildingDevice.setUpdateBy(SecurityUtils.getUserId().toString());
                buildingDevice.setDeviceId(e);
                buildingDeviceService.insertBuildingDevice(buildingDevice);
            });
        }
        return AjaxResult.success();
    }

    @Override
    public AjaxResult getBuildingDevices(Long buildingId) {

        return AjaxResult.success(accessDeviceMapper.getBuildingDevices(SecurityUtils.getParkId(), buildingId));
    }


    @Override
    public AjaxResult selectBuildingList(RemoteBuildingListRequest request) {

        Map<String, Object> map = new HashMap<>(2);
        map.put("list", new ArrayList<>());
        map.put("total", 0);

        BuildingListSearch search = OrikaUtil.convert(request, BuildingListSearch.class);
        search.setParkId(request.getProjectId());
        IPage<BuildBuildingV1> page = buildBuildingService.selectBuildBuildingPageV1(search);
        if (CollectionUtils.isEmpty(page.getRecords())) {
            return AjaxResult.success(map);
        }
        List<Long> areaIds = page.getRecords().stream().map(BuildBuildingV1::getAreaId).distinct().collect(Collectors.toList());

        List<BuildAreaV1> areaList = areaService.listByIds(areaIds);
        Map<Long, BuildAreaV1> areaMap = areaList.stream().collect(Collectors.toMap(BuildAreaV1::getId, item -> item));

        List<BuildingListVO> vos = OrikaUtil.converts(page.getRecords(), BuildingListVO.class);
        vos.forEach(item -> {
            if (StringUtils.isNotNull(areaMap.get(item.getAreaId()))) {
                item.setAreaName(areaMap.get(item.getAreaId()).getAreaName());
            }
        });

        map.put("list", vos);
        map.put("total", page.getTotal());

        return AjaxResult.success(map);
    }

    @Override
    public AjaxResult getBuildingList(BuildBuildingListRequest request) {

        List<BuildBuilding> list = buildBuildingService.selectBuildBuildingListByAreaIds(request.getAreaIds());

        List<BuildingListVO> vos = OrikaUtil.converts(list, BuildingListVO.class);

        Map<Long, List<BuildingListVO>> map = vos.stream().collect(Collectors.toMap(
                BuildingListVO::getAreaId,
                v -> new ArrayList<>(Collections.singletonList(v)),
                (List<BuildingListVO> oldList, List<BuildingListVO> newList) -> {
                    oldList.addAll(newList);
                    return oldList;
                }
        ));

        return AjaxResult.success(map);
    }
}
